/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2019 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */
/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "adc.h"
#include "iwdg.h"
#include "usart.h"
#include "rtc.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "store.h"
#include "utils.h"
#include "active.h"
#include "message_queue.h"
#include "ctimer.h"
#include "hw.h"
#include "serial.h"
#include "mstdio.h"
#include "shell.h"
#include "power_manager.h"
#include "at_command.h"
#include "net.h"
#include "detector.h"
#include "battery.h"
#include "door.h"
#include "speaker.h"
#include "load.h"
#include "resource.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */
static int _Reset(Stream_t *stream, int argc, char *argv[]);
static void _MsgDeliver(MsgQueue_Msg_t *msg);

// 串口命令列表
static const Shell_Cmd_t _shellCmds[] =
{
        {"help", Shell_Help, "Show shell command help message.", "[<command name>]"},
//        {"version", Shell_Version, "Show version info.", ""},
        {"test", Shell_Test, "For shell test.", "[<arg 1>] [<arg 2>]...[<arg n>]"},
        {"in", HW_IoInCmd, "Show input pin level", "[<pin name>]"},
        {"out", HW_IoOutCmd, "Show or set output pin level", "[<pin name>] [0|1]"},
        {"bridge", Shell_Bridge, "Build bridge from stdio to other serial", "<serial index>"},
        {"reset", _Reset, "Reset the MCU", ""},
        {"notify", Resource_NotifyCmd, "Start notify", "<resource> <data type> <value>"},
        {"abort", Net_NotifyAbortCmd, "Abort notification", ""},
        {"id", AtCommand_ReadIdCmd, "Read out IMEI and IMSI", ""},
        {"battery", Battery_MeasureCmd, "Battery status", ""},
        {"lock", Door_OpenCmd, "Show lock status or open lcok", "[<lock index>]"},
        {"speak", Speaker_SpeakCmd, "play a sound", "[<short name of the sound>]"},
        {"at", AtCommand_ShellCmd, "Send AT CMD string to RF module", "[<Sub command> [<timeout(ms)>]]"},
        {"AT", AtCommand_ShellCmd, "Send AT CMD string to RF module", "[<Sub command> [<timeout(ms)>]]"},
        {"load", Load_ShellCmd, "Get load reading and status", ""},
};
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */
    Ctimer_Init();
  /* USER CODE END 1 */
  

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */
#if 0
  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_IWDG_Init();
  MX_LPUART1_UART_Init();
  MX_USART1_UART_Init();
  MX_USART4_UART_Init();
  MX_USART5_UART_Init();
  MX_ADC_Init();
  MX_RTC_Init();
  /* USER CODE BEGIN 2 */
#endif
  Store_Init();
  MX_GPIO_Init();
  Utils_Init();
  Active_Init();
  MsgQueue_Init(_MsgDeliver);
  HW_Init();
  Serial_Init();
  MStdio_Init();
  Shell_Init(_shellCmds, ARRAY_SIZE(_shellCmds));
  Door_Init();
  PowerManager_Init();
  AtCommand_Init(Resource_OnWrite);
  Resource_Init();
  Net_Init();
  Detector_Init();
  Battery_Init();
  Speaker_Init();
  Load_Init();
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  ON_DEBUG(Store_Test());
  Serial_TestCmd(Serial_4, ENABLE);
  while (1)
  {
      MsgQueue_Service();
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
      PowerManager_TryToStop();
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};

  /** Configure the main internal regulator output voltage 
  */
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
  /** Configure LSE Drive Capability 
  */
  HAL_PWR_EnableBkUpAccess();
  __HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_LOW);
  /** Initializes the CPU, AHB and APB busses clocks 
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI|RCC_OSCILLATORTYPE_HSE
                              |RCC_OSCILLATORTYPE_LSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.LSEState = RCC_LSE_ON;
  RCC_OscInitStruct.LSIState = RCC_LSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB busses clocks 
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSE;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
  {
    Error_Handler();
  }
  PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1|RCC_PERIPHCLK_LPUART1
                              |RCC_PERIPHCLK_RTC;
  PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_SYSCLK;
  PeriphClkInit.Lpuart1ClockSelection = RCC_LPUART1CLKSOURCE_LSE;
  PeriphClkInit.RTCClockSelection = RCC_RTCCLKSOURCE_LSI;
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */
/**
 * @brief 处理消息
 * @param msg 消息指针
 */
static void _MsgDeliver(MsgQueue_Msg_t *msg)
{

//    debug("MQ: Dealing msg id: %d\n", msg->id);

    switch(msg->id)
    {
    case MsgQueue_Id_ShellLineIn:
        Shell_OnLine(msg);
        break;

    case MsgQueue_Id_CtimerFire:
        Ctimer_Fire(msg);
        break;

    case MsgQueue_Id_SerialTest:
        Serial_OnTest(msg);
        break;

    case MsgQueue_Id_SerialSend:
        Shell_OnSerialSend(msg);
        break;

    case MsgQueue_Id_ExtiTest:
        HW_OnExtiMsg(msg);
        break;

    case MsgQueue_Id_AtEvent:
        AtCommand_OnEvent(msg);
        break;

    case MsgQueue_Id_MiplEvent:
        Net_OnMiplEvent(msg);
        break;

    case MsgQueue_Id_SlaveFrameIn:
//        Slave_OnFrameIn(msg);
        break;

    case MsgQueue_Id_Detector:
//        Net_OnDeliver(msg);
        break;

    case MsgQueue_Id_Notified:
        Detector_OnNotified(msg);
        break;

    case MsgQueue_Id_MiplDiscoverObj:
        Net_OnMiplDiscoverObj(msg);
        Resource_OnMiplDiscoverObj(msg);
        break;

    case MsgQueue_Id_Speak:
        Speaker_OnSpeak(msg);
        break;

    case MsgQueue_Id_RoutineDetect:
        Detector_OnRoutine(msg);
        break;

    case MsgQueue_Id_DoorAction:
        Detector_OnDoorAction(msg);
        break;

    case MsgQueue_Id_Heartbeat:
    	Resource_OnHeartbeat(msg);
    	break;

    default:
        debug("Error: Unknown Message, id = %d!\n", msg->id);
        break;
    }
}

static int _Reset(Stream_t *stream, int argc, char *argv[])
{
    printf("System Reset!\r\n");
    Utils_DelayMs(5);
//    __disable_fault_irq();
    HAL_NVIC_SystemReset();
    return 0;
}

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */

  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{ 
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
    printf("Assert Fail: file %s on line %ld\r\n", file, line);
    while(1);
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
